//
//  JRQRCodeManager.swift
//  JRQRCode
//
//  Created by 京睿 on 2017/4/22.
//  Copyright © 2017年 JingRuiWangKe. All rights reserved.
//

import UIKit
import AVFoundation

public class JRQRCodeManager: NSObject {
    public weak var JRDelegate: JRQRCodeManagerDelegate!
    fileprivate var captureSession: AVCaptureSession?
    public var isRunning: Bool {
        guard let captureSession = captureSession  else { return false }
        return captureSession.isRunning
    }
    
    private override init() { }
    
    /// 初始化manager
    ///
    /// - Parameters:
    ///   - view: 添加扫描框的view
    ///   - boxFrame: 扫描框相对于view的位置
    /// - Returns: manger
    @discardableResult
    public class func manger(for view: UIView, boxFrame: CGRect) -> JRQRCodeManager {
        let manger = JRQRCodeManager()
        if permission() {
            manger.qr(for: view, boxFrame: boxFrame)
        } else {
            requestPermission { (b) in
                DispatchQueue.main.async {
                    if b {
                        manger.qr(for: view, boxFrame: boxFrame)
                    } else {
                        manger.JRDelegate?.JRQRCodeManger(manger, initializeFailed: nil)
                    }
                }
            }
        }
        return manger
    }
    
    /// 查看相机权限
    ///
    /// - Returns: return value description
    private class func permission() -> Bool {
        let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        switch status {
        case .notDetermined, .denied, .restricted:
            return false
            
        case .authorized:
            return true
        }
    }
    
    private class func requestPermission(_ completionHandler: ((Bool)->())!) {
        AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: completionHandler)
    }
    
    private func qr(for view: UIView, boxFrame: CGRect) {
        do {
            guard let device  = AVCaptureDevice.default(for: AVMediaType.video) else { return }
            let input   = try AVCaptureDeviceInput.init(device: device)
            let output  = AVCaptureMetadataOutput()
            output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            
            captureSession = AVCaptureSession()
            captureSession?.sessionPreset = AVCaptureSession.Preset.high
            if let isCan = captureSession?.canAddInput(input), isCan {
                captureSession?.addInput(input)
            }
            if let isCan = captureSession?.canAddOutput(output), isCan {
                captureSession?.addOutput(output)
            }
            
            output.metadataObjectTypes = [
                AVMetadataObject.ObjectType.code128,
                AVMetadataObject.ObjectType.upce,
                AVMetadataObject.ObjectType.code39,
                AVMetadataObject.ObjectType.code39Mod43,
                AVMetadataObject.ObjectType.ean13,
                AVMetadataObject.ObjectType.ean8,
                AVMetadataObject.ObjectType.code93,
                AVMetadataObject.ObjectType.pdf417,
                AVMetadataObject.ObjectType.qr,
                AVMetadataObject.ObjectType.aztec,
                AVMetadataObject.ObjectType.interleaved2of5,
                AVMetadataObject.ObjectType.itf14,
                AVMetadataObject.ObjectType.dataMatrix
            ]
            
            let layer = AVCaptureVideoPreviewLayer.init(session: captureSession!)
            layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            layer.frame = view.layer.bounds
            view.layer.insertSublayer(layer, at: 0)
            
            captureSession?.startRunning()
            
            let ll = layer.metadataOutputRectConverted(fromLayerRect: boxFrame)
            output.rectOfInterest = ll
        } catch {
            print(error.localizedDescription)
        }
    }
}

public extension JRQRCodeManager {
    public func startScan() {
        captureSession?.startRunning()
    }
    
    public func stopScan() {
        captureSession?.stopRunning()
    }
}

// MARK: - AVCaptureMetadataOutputObjectsDelegate
extension JRQRCodeManager: AVCaptureMetadataOutputObjectsDelegate {
    public func metadataOutput(captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        guard let metadataObjects = metadataObjects as? [AVMetadataMachineReadableCodeObject] else { return }
        let real = metadataObjects.flatMap { (result) -> JRQRCodeModel? in
            let model = JRQRCodeModel()
            model.type = result.type.rawValue
            model.bounds = result.bounds
            model.corners = result.corners
            model.stringValue = result.stringValue
            model.time = result.time.value
            return model
        }
        JRDelegate?.JRQRCodeManger(self, update: real)
    }
    
    public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        guard let metadataObjects = metadataObjects as? [AVMetadataMachineReadableCodeObject] else { return }
        let real = metadataObjects.flatMap { (result) -> JRQRCodeModel? in
            let model = JRQRCodeModel()
            model.type = result.type.rawValue
            model.bounds = result.bounds
            model.corners = result.corners
            model.stringValue = result.stringValue
            model.time = result.time.value
            return model
        }
        JRDelegate?.JRQRCodeManger(self, update: real)
    }
}
